package com.toulezu.test.aop;

import com.ckjava.xutils.ExceptionUtils;
import com.ckjava.xutils.StringUtils;
import com.ckjava.xutils.http.HttpResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

@Aspect
@Component
@Order(2)
public class OpLogAop extends AopBase {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Around("controllerPointCut()")
    public void handleLog(ProceedingJoinPoint joinPoint) {
        long begin = System.currentTimeMillis();

        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();

        // 记录下请求内容
        String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        String methodArgs = Arrays.toString(joinPoint.getArgs());

        String httpMethod = request.getMethod();
        String requestURI = request.getRequestURL().toString();
        String remoteAddr = getIpAddr(request);
        String queryString = request.getQueryString();
        String pathInfo = request.getPathInfo();
        // 处理请求头
        StringBuilder headerStr = new StringBuilder();
        for (Enumeration<?> header = request.getHeaderNames(); header.hasMoreElements();) {
            String name = StringUtils.getStr(header.nextElement());
            String value = request.getHeader(name);
            headerStr.append(name).append(SPLITER.EQUAL).append(value).append(SPLITER.AND);
        }

        List<String> infoList = new ArrayList<>();
        StringBuilder infoLog = new StringBuilder();
        infoLog.append("classMethod:{},");
        infoList.add(classMethod);
        infoLog.append("methodArgs:{},");
        infoList.add(methodArgs);
        infoLog.append("remoteAddr:{},");
        infoList.add(remoteAddr);
        infoLog.append("httpMethod:{},");
        infoList.add(httpMethod);
        infoLog.append("requestURI:{},");
        infoList.add(requestURI);
        infoLog.append("queryString:{},");
        infoList.add(queryString);
        infoLog.append("pathInfo:{},");
        infoList.add(pathInfo);
        infoLog.append("requestHeader:{},");
        infoList.add(headerStr.toString());

        // 目标方法的处理
        Object returnObj = null;
        try {
            returnObj = joinPoint.proceed();
        } catch (Throwable e) {
            infoLog.append("errorInfo:{}");
            infoList.add(ExceptionUtils.getExceptionMsg(e));
            logger.error(infoLog.toString(), infoList.toArray(new Object[infoList.size()]), e);

            // 处理异常
            processResponse(response, HttpResponse.getReturn(e));
        } finally {
            long consumeTime = System.currentTimeMillis() - begin;
            infoLog.append("consumeTime:{}");
            infoList.add(String.valueOf(consumeTime));
            logger.info(infoLog.toString(), infoList.toArray(new Object[infoList.size()]));

            // 返回响应内容给客户端
            response.setHeader("consumeTime", consumeTime + " ms");
            processResponse(response, returnObj);
        }
    }

}
